home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 8
/
Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso
/
Aminet
/
util
/
wb
/
opticon_1_9.lha
/
opticon-1.9
/
opticon.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-07-16
|
20KB
|
656 lines
/*
* OPTICON.C
*/
#include "version.h"
static char versiontag[] = "$VER: $Id: opticon.c,v 1.9 1995/07/14 17:38:41 tf Exp $";
/****** OptIcon/OptIcon ******************************************************
*
* NAME
* OptIcon -- Optimize icon images for size and speed (V36)
*
* SYNOPSIS
* OptIcon NAME/A/M,DEPTH=PLANES/N,NOEXPAND/S,VERBOSE/S,SMART/S
*
* FUNCTION
* OptIcon reads in given ".info" files and scans the icon image
* in order to optimize the PlanePick and PlaneOnOff fields in the
* icon Image structure. This is a space-saving mechanism for image
* data.
* Rather than defining the image data for every plane of the RastPort,
* you need define data only for the planes that are not entirely zero
* or one. As you define your Imagery, you will often find that most
* of the planes ARE just as color selectors. For instance, if you're
* designing a two-color icon to use colors one and three, and the icon
* will reside in a five-plane display, bit plane zero of your
* imagery would be all ones, bit plane one would have data that
* describes the imagery, and bit planes two through four would be
* all zeroes. Using these flags avoids wasting all that memory in
* this way: first, you specify which planes you want your data to
* appear in using the PlanePick variable. For each bit set in the
* variable, the next "plane" of your image data is blitted to the
* display. For each bit clear in this variable, the corresponding bit
* in PlaneOnOff is examined. If that bit is clear, a "plane" of zeroes
* will be used. If the bit is set, ones will go out instead.
* Note that if you want an Image that is only a filled rectangle, you
* can get this by setting PlanePick to zero (pick no planes of data)
* and set PlaneOnOff to describe the pen color of the rectangle.
*
* INPUTS
* NAME - name of the icon image file. A trailing ".info"
* is optional but not required.
* DEPTH - maximum number of bitplanes to be saved.
* VERBOSE - display input and output information for each icon.
*
* EXAMPLE
* ;Remove all but the first 3 planes of the icon image for the
* ;disk in drive DF0: but don't add any planes
* opticon df0:disk planes=3 noexpand
*
* NOTES
* Since the IconEdit from Commodore will always save 8 bitplane icons
* the above example might be of great use to you. (Note that 3 plane
* images are not only smaller but also faster!)
* Coming with OptIcon is the script PatchIcons which will recursively
* descend all subdirectories of a given path deleting all but the first
* 3 planes of all icon images in that path.
*
* OptIcon now also allows you to expand your 8 or more color icons
* for the use on a 16 or more color Workbench. This is important due
* to the new color system under OS3.x which always shifts the second
* four colors to the end of the system palette. Therefore you might
* want to adapt an icon's color depth to the actual screenmode it is
* used on.
*
* EXAMPLE
* ;Remap the last 4 of at least 8 colors of the RAM DISK icon
* ;to the last 4 colors in a 16 or more colors Workbench palette
* opticon ram:disk planes=4
*
* NOTE ALSO
* With the new option SMART/S OptIcon will examine WBDRAWER icons
* more closely and if there is not really a drawer (or a file 8-)
* behind the icon then the icon type is changed into WBTOOL. This
* is a great help if you want to use some drag'n drop application to
* update icon images which would have problems otherwise.
*
* BUGS
* Commodore's PutDiskObject() currently [icon.library 40.1 (15.2.93)]
* re-expands icon images using the PlanePick/PlaneOnOff mechanism and
* in fact PutDiskObject() has quite a lot of problems doing so!
* For this reason OptIcon will perform the PlanePick/PlaneOnOff
* optimization only if the keyword CRITICAL is given in the command
* line.
*
* DISCLAIMER
* This file is part of the Icon2C and OptIcon distribution.
*
* Icon2C and OptIcon are free software; you can redistribute them
* and/or modify them under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 1 of
* the License, or (at your option) any later version.
*
* Icon2C and Opticon are distributed in the hope that they will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with these programs; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* COPYRIGHT
* Icon2C and OptIcon are Copyright (C)1994 by Tobias Ferber.
* You can reach me via E-mail: ukjg@rz.uni-karlsruhe.de
*
* SEE ALSO
* PatchIcons, Icon2C
*
******************************************************************************
*
* Compile w/ -DDEBUG to output more information at runtime
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/rdargs.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <workbench/icon.h>
#include "memfn.h"
#ifdef __GNUC__
/* suggest parentheses around assignment used as truth value */
#define if(assignment) if( (assignment) )
#endif /* __GNUC__ */
extern struct Library *OpenLibrary(STRPTR, ULONG);
extern void CloseLibrary(struct Library *);
extern void CopyMem(APTR, APTR, ULONG);
extern void *AllocMem(ULONG, ULONG);
extern void FreeMem(void *, ULONG);
extern ULONG TypeOfMem(void *);
extern struct RDArgs *ReadArgs(STRPTR, LONG *, struct RDArgs *);
extern LONG IoErr(void);
extern BOOL PrintFault(LONG, STRPTR);
extern void FreeArgs(struct RDArgs *);
extern struct DiskObject *GetDiskObject(char *);
extern BOOL PutDiskObject(char *, struct DiskObject *);
extern void FreeDiskObject(struct DiskObject *);
struct IconBase *IconBase;
void display_version_information(void)
{
static char license[]=
"OptIcon is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published\n"
"by the Free Software Foundation; either version 1 of the License,\n"
"or (at your option) any later version.\n"
"\n"
"OptIcon is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with OptIcon; see the file COPYING. If not, write to the\n"
"Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
;
puts("\nOptIcon Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
"(c)Copyright 1994 by Tobias Ferber, ukjg@rz.uni-karlsruhe.de\n");
puts(license);
}
struct Image *free_image(struct Image *i)
{
if(i)
{
long size= i->Depth * i->Height * ((i->Width + 15) / 16) * sizeof(UWORD);
if(i->ImageData && size > 0)
FreeMem( i->ImageData, size );
FreeMem( i, sizeof(struct Image) );
}
return (struct Image *)0L;
}
/* command line options */
#define OPT_NOEXPAND (1<<0)
#define OPT_CRITICAL (1<<1)
#define OPT_VERBOSE (1<<2)
#define OPT_REMAPV37 (1<<3)
struct Image *optimize_image(struct Image *i, WORD planes, int optimode)
{
UWORD p16= i->Height * ((i->Width + 15) / 16); /* #of words per plane */
UWORD *idata= i->ImageData;
WORD d, dmax, D, P;
UBYTE pp= 0; /* plane pick */
UBYTE p10= 0; /* plane on/off */
struct Image *o= i; /* optimized image */
/* prevent silly args from being harmful */
if(!i)
return i;
if(planes > 8)
planes= 8;
if(optimode & OPT_VERBOSE)
{
printf("(depth=%d, pick=%d, onoff=%d)", i->Depth,
i->PlanePick,
i->PlaneOnOff);
fflush(stdout);
}
/*
PRESCAN: Examine dmax planes of i and compute
D = the real depth (without trailing 0 planes)
pp = the new PlanePick value
p10 = the new PlaneOnOff value
*/
dmax= (0 < planes && planes < i->Depth) ? planes : i->Depth;
for(d= D= 0; d<dmax; d++)
{
/* check if we have some image data for plane d */
if(i->PlanePick & (1<<d))
{
UWORD n, *p, v;
/* scan the image data of plane d */
for(n=0, p=idata, v=*p; n < p16; n++, p++)
if(*p != v)
break;
if(n==p16 && v==0xFFFF) /* plane d is entirely 1 */
p10 |= (1<<d); /* pp bit is already 0 */
if( n!=p16 || (n==p16 && v!=0x0000 && v!=0xFFFF) )
pp |= (1<<d);
if( n!=p16 || (n==p16 && v!=0x0000) )
D= d;
idata= &idata[p16];
}
else if(i->PlaneOnOff & (1<<d))
{
p10 |= (1<<d);
D=d;
}
}
++D;
if( (optimode & OPT_VERBOSE) && (D != dmax || pp != i->PlanePick || p10 != i->PlaneOnOff) )
{
printf(" -> (%d,%d,%d)", D,pp,p10);
fflush(stdout);
}
/* compute the #of planes in the output image */
P= ( planes>D && !(optimode & OPT_NOEXPAND) ) ? planes : D;
if(P != i->Depth || pp != i->PlanePick || p10 != i->PlaneOnOff)
{
UWORD p8= p16 * sizeof(UWORD);
UWORD *odata;
ULONG osize= P * p8;
if( o= (struct Image *)AllocMem(sizeof(struct Image),MEMF_CLEAR) )
{
if( odata= (UWORD *)AllocMem(osize,TypeOfMem(i->ImageData)|MEMF_CLEAR) )
{
CopyMem( (APTR)i, (APTR)o, sizeof(struct Image) );
o->ImageData= odata;
idata= i->ImageData;
for(d=0; d<D; d++)
{
if( pp & (1<<d) )
{
if(i->PlanePick & (1<<d))
{
CopyMem( (APTR)idata, (APTR)odata, p8 );
idata= &idata[p16];
odata= &odata[p16];
}
else /* !PlanePick bit (should not happen) */
{
memset( (char *)odata, (i->PlaneOnOff & (1<<d)) ? 0xFF : 0x00, p8 );
odata= &odata[p16];
}
}
else /* !pp bit */
{
if(i->PlanePick & (1<<d))
idata= &idata[p16];
if( !(optimode & OPT_CRITICAL) )
{
memset( (char *)odata, (p10 & (1<<d)) ? 0xFF : 0x00, p8 );
odata= &odata[p16];
pp |= (1<<d);
p10 &= ~(1<<d);
}
}
}
if(D>=3 && D<P) /* no need to check OPT_NOEXPAND sice P is < D if set */
{
UWORD *p;
if( p= (UWORD *)malloc(p8) )
{
if( (optimode & OPT_REMAPV37) && p10<=7 )
{
/*
REMAP: Make colors 4-7 become the last 4 in the palette
Algo: (1) OR together all planes > 2,
(2) invert the result,
(3) AND it with plane 2 and
(4) OR the result with all planes > 2
Note: There is no need to expand the image data if p10 &~ %111 != 0
*/
/* move to plane 2 */
idata= i->ImageData;
for(d=0; d<2; d++)
if(i->PlanePick & (1<<d))
idata= &idata[p16];
if(i->PlanePick & (1<<2))
{
memcpy((char *)p, (char *)idata, p8);
idata= &idata[p16];
}
else memset( (char *)p, (p10 & (1L<<2)) ? 0xFF : 0x00, p8 );
/* or planes 3..D, invert them, AND the result with plane 2 */
for(d=3; d<D; d++)
{
if(i->PlanePick & (1<<d))
{
memandnot( (char *)p, (char *)idata, p8 );
idata= &idata[p16];
}
/* else bit d of i->PlaneOnOff is 0 --> no-op */
}
/* move to plane 3 */
odata= o->ImageData;
for(d=0; d<3; d++)
if(pp & (1<<d))
odata= &odata[p16];
for(d=3; d<P; d++)
{
if( d>=D || pp & (1<<d) )
{
memor( (char *)odata, (char *)p, p8 );
odata= &odata[p16];
pp |= (1<<d);
}
}
}
else /* !REMAPV37 */
{
/*
EXPAND: Remap the last 4 colors of i to the last 4 colors of o
Algo: (1) OR together all planes but the last
(2) AND the result with the last plane
(3) set the result in all new planes
Note: if any plane of i but the last is entirely 1 then we can
simply copy the last plane of i to all new planes in o
*/
idata= i->ImageData;
if( p10 &~ (1<<(D-1)) == 0)
{
memset( (char *)p, 0x00, p8 );
for(d=0; d<D-1; d++)
{
if(i->PlanePick & (1<<d))
{
memor( (char *)p, (char *)idata, p8 );
idata= &idata[p16];
}
}
/* else plane d is entirely 0 */
if( i->PlanePick & (1<<(D-1)) )
memand( (char *)p, (char *)idata, p8 );
/* else the last plane is entirely 1 */
}
else /* move to the last plane */
{
for(d=0; d<D-1; d++)
if(i->PlanePick & (1<<d))
idata= &idata[p16];
if( i->PlanePick & (1<<(D-1)) )
memcpy( (char *)p, (char *)idata, p8 );
else
memset( (char *)p, 0xFF, p8 );
}
/* move to plane D */
odata= o->ImageData;
for(d=0; d<D; d++)
if(pp & (1<<d))
odata= &odata[p16];
for(d=D; d<P; d++)
{
memcpy( (char *)odata, (char *)p, p8 );
odata= &odata[p16];
pp |= (1<<d);
}
}
free(p);
}
else /* !p --> panic! */
{
FreeMem(o->ImageData,osize);
FreeMem(o,sizeof(struct Image));
o= (struct Image *)0L;
}
}
o->Depth= P;
o->PlanePick= pp;
o->PlaneOnOff= p10;
}
else /* !odata */
{
FreeMem(o,sizeof(struct Image));
o= (struct Image *)0L;
}
}
}
if(optimode & OPT_VERBOSE)
{
if(o && o!=i)
printf(" -> (%d,%d,%d)", o->Depth, o->PlanePick, o->PlaneOnOff);
putchar('\n');
}
return o;
}
int main(int argc, char **argv)
{
struct RDArgs *a;
LONG args[7] = { 0,0,0,0,0,0,0 };
WORD numplanes= 0;
char *whoami= *argv;
int rc= RETURN_OK;
if( a= ReadArgs("NAME/A/M,DEPTH=PLANES/N,NOEXPAND/S,CRITICAL/S,REMAPV37/S,VERBOSE/S,SMART/S", args, NULL) )
{
char **flist= (char **)args[0];
if(args[1])
{
if( (numplanes= (WORD)*(LONG *)(args[1])) < 1 )
{
fprintf(stderr,"%s: Illegal maximum depth %d\n",whoami,numplanes);
rc= RETURN_FAIL;
}
}
if(flist && rc == RETURN_OK)
{
if( IconBase= (struct IconBase *)OpenLibrary(ICONNAME,36) )
{
while(*flist && rc == RETURN_OK)
{
char *iname= (char *)malloc( strlen(*flist) + 1 );
if(iname)
{
struct DiskObject *icon;
strcpy(iname, *flist);
if( (icon= GetDiskObject(iname)) == NULL )
{
int x= strlen(iname) - 5;
if(x>0 && !stricmp(&(iname[x]),".info"))
{
iname[x]= '\0';
icon= GetDiskObject(iname);
}
}
if(icon)
{
struct Gadget *g= &icon->do_Gadget;
struct Image *ogr, *osr;
int modified= 0;
int flags= 0;
ogr= osr= (struct Image *)0L;
if(args[2]) flags |= OPT_NOEXPAND;
if(args[3]) flags |= OPT_CRITICAL;
if(args[4]) flags |= OPT_REMAPV37;
if(args[5]) flags |= OPT_VERBOSE;
if(g->GadgetRender && (g->Flags & GFLG_GADGIMAGE))
{
struct Image *i= (struct Image *)g->GadgetRender;
if(flags & OPT_VERBOSE)
printf("Normal ");
if( ogr= optimize_image(i,numplanes,flags) )
{
if(ogr != i)
{
g->GadgetRender= (APTR)ogr;
++modified;
}
else ogr= (struct Image *)0L; /* don't free ogr */
if(g->SelectRender && (g->Flags & GFLG_GADGHIMAGE))
{
i= (struct Image *)g->SelectRender;
if(flags & OPT_VERBOSE)
printf("Selected ");
if( osr= optimize_image(i,numplanes, flags) )
{
if(osr != i)
{
g->SelectRender= (APTR)osr;
++modified;
}
else osr= (struct Image *)0L; /* don't free osr */
}
else
{
fprintf(stderr,"%s: %s.info: not enough free memory to optimize the selected image\n",whoami,iname);
rc= RETURN_ERROR;
}
}
}
else
{
fprintf(stderr,"%s: %s.info: not enough free memory to optimize the normal image\n",whoami,iname);
rc= RETURN_ERROR;
}
}
/* SMART/S */
if( rc == RETURN_OK && args[6] && icon->do_Type == WBDRAWER )
{
BPTR lock= Lock(iname,ACCESS_READ);
if( BADDR(lock) )
UnLock(lock);
else
{
icon->do_Type = WBTOOL;
++modified;
}
}
if( modified && rc == RETURN_OK )
{
if( !PutDiskObject(iname,icon) )
PrintFault(rc= IoErr(), iname);
}
if(ogr) ogr= free_image(ogr);
if(osr) osr= free_image(osr);
FreeDiskObject(icon);
}
else /* !icon */
{
fprintf(stderr,"%s: GetDiskObject() failed for %s[.info]\n",whoami,iname);
rc= IoErr();
}
free(iname);
}
else /* !iname */
{
fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
rc= RETURN_ERROR;
}
++flist;
}
CloseLibrary((struct Library *)IconBase);
}
else
{
fprintf(stderr,"%s: You need %s V36+",whoami,ICONNAME);
rc= RETURN_ERROR;
}
}
FreeArgs(a);
}
else /* !ReadArgs */
{
if(argc == 1)
display_version_information();
else
PrintFault(IoErr(), NULL);
}
exit(rc);
}